package business;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;

import utils.HibernateUtil;

import entities.Boek;
import entities.Lening;
import entities.Lid;

public class LeningZoeker implements IEntityZoeker<Lening>
{
	/**
	 * De vergelijkingsoperator wordt toegepast op Date objecten. <br />
	 * resultaat.date < date <br />
	 * resultaat.date <= date <br />
	 * resultaat.date == date <br />
	 * resultaat.date >= date <br />
	 * resultaat.date > date <br />
	 */
	public enum Operator{SMALLER, SMALLER_EQUAL, EQUAL, GREATER_EQUAL, GREATER};
	
	private List<Lening> results;
	private boolean changed = true;
	
	private Calendar einddatum;
	private Operator einddatumOp;
	private Calendar ingeleverd;
	private Operator ingeleverdOp;
	private Boolean isIngeleverd;
	private Boek boek;
	private Lid lid;
	
	// Constructor
	
	public LeningZoeker()
	{
		einddatumOp = Operator.GREATER_EQUAL;
		ingeleverdOp = Operator.GREATER_EQUAL;
	}
	
	// Getters en Getters
	
	public Calendar getEinddatum()
	{
		return einddatum;
	}
	public void setEinddatum(Calendar einddatum)
	{
		changed = true;
		this.einddatum = einddatum;
	}
	public Operator getEinddatumOp()
	{
		return einddatumOp;
	}
	public void setEinddatumOp(Operator einddatumOp)
	{
		this.einddatumOp = einddatumOp;
	}
	public Calendar getIngeleverd()
	{
		return ingeleverd;
	}
	/**
	 * De datum waarop het geleende boek is ingeleverd. Als de datum niet null is
	 * wordt de boolean isIngeleverd ingesteld op true (isIngeleverd(true)).
	 * @param ingeleverd De inleverdatum
	 */
	public void setIngeleverd(Calendar ingeleverd)
	{
		changed = true;
		this.ingeleverd = ingeleverd;
		
		if(einddatum == null)
		{
			isIngeleverd = false;
		}
		else
		{
			isIngeleverd = true;
		}
	}
	public Operator getIngeleverdOp()
	{
		return ingeleverdOp;
	}
	public void setIngeleverdOp(Operator ingeleverdOp)
	{
		this.ingeleverdOp = ingeleverdOp;
	}
	public Boek getBoek()
	{
		return boek;
	}
	public void setBoek(Boek boek)
	{
		changed = true;
		this.boek = boek;
	}
	public Lid getLid()
	{
		return lid;
	}
	public void setLid(Lid lid)
	{
		changed = true;
		this.lid = lid;
	}
	/**
	 * Kijkt of het geleende book is ingeleverd. Dit negeert de datum waarop het is ingeleverd
	 * (getIngeleverd(), setIngeleverd()).
	 * @return
	 */
	public Boolean isIngeleverd()
	{
		return isIngeleverd;
	}
	public void isIngeleverd(Boolean isIngeleverd)
	{
		this.isIngeleverd = isIngeleverd;
	}
	
	@Override
	public List<Lening> zoek()
	{
		if(changed)
		{
			Session session = HibernateUtil.getSessionFactory().openSession();
			String queryString = "FROM entities.Lening";
			
			queryString += getWhereStatements();
			
			System.out.println(queryString);
			
			Query query = session.createQuery(queryString);
			
			results = query.list();
			
			session.close();
			
			changed = false;
		}
		
		return results;
	}
	
	private String getWhereStatements()
	{
		String wh = "";
		
		if(lid != null)
		{
			if(!wh.isEmpty())
			{
				wh += " AND";
			}
			
			wh += " lid.id = " + lid.getId();
		}
		if(boek != null)
		{
			if(!wh.isEmpty())
			{
				wh += " AND";
			}
			
			wh += " boek.id = " + boek.getId();
		}
		if(isIngeleverd != null)
		{
			if(!wh.isEmpty())
			{
				wh += " AND";
			}
			
			if(isIngeleverd == false)
			{
				wh += " ingeleverd IS NULL";
			}
			else
			{
				wh += " ingeleverd IS NOT NULL";
			}
		}
		if(ingeleverd != null)
		{
			try
			{
				if(!wh.isEmpty())
				{
					wh += " AND";
				}
				
				String datum = getCalendarString(ingeleverd);
				
				wh += " ingeleverd" + getOperatorString(ingeleverdOp) + datum; 
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		if(einddatum != null)
		{
			try
			{
				if(!wh.isEmpty())
				{
					wh += " AND";
				}
				
				String datum = getCalendarString(einddatum);
				
				wh += " einddatum" + getOperatorString(einddatumOp) + datum; 
			}
			catch(Exception e)
			{
				e.printStackTrace();
			}
		}
		
		if(!wh.isEmpty())
		{
			wh = " WHERE" + wh;
		}
		
		return wh;
	}
	
	private String getCalendarString(Calendar cal)
	{
		int year = cal.get(Calendar.YEAR);
		int month = cal.get(Calendar.MONTH) + 1;
		int day = cal.get(Calendar.DAY_OF_MONTH);
		
		return String.format(
				"\'%2d-%2s-%2s\'",
				year,
				month < 10 ? ("0" + month) : month,
				day < 10 ? ("0" + day) : day);
	}
	
	private String getOperatorString(Operator operator)
			throws Exception
	{
		switch(operator)
		{
		case EQUAL: return " = ";
		case GREATER: return " > ";
		case GREATER_EQUAL: return " >= ";
		case SMALLER: return " < ";
		case SMALLER_EQUAL: return " <= ";
		default: throw new Exception("Illegal LeningZoeker Operator: " + operator);
		}
	}
}
